import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import actions from './actions'
import mutations from './mutations'
import getters from './getters'
import cart from './modules/cart'
import products from './modules/products'

Vue.use(Vuex)

/**
 *  由于在store中的状态是响应式的
 *    一、 将 store 放在vue实例中去，实现 根组件 注入到每个 子组件
 *    二、 vuex 并不意味着将运用程序的的所有状态都放进 vuex 中去，
 *        如果一个变量严格属于一个组件，最好将其放在组件中
 *    二、
 *      A、 @state
 *      -   1、 调用时，仅需在计算属性中返回即可
 *              例：computed:{ done(){ return this.$store.state.num }}
 *              -
 *          2、 触发变化也仅仅是在组件的methods中提交（commit） mutation （变化） 中的方法
 *              例：  methods:{increment(){ this.$store.commit('increment')} }
 *              -
 *          3、 当一个组件需要获取多个状态时，把这些状态都声明为计算属性会有些重复和冗余,
 *              我们使用 mapState 辅助函数帮助我们完成计算
 *              例：  computed:{ ...mapState(['NUM','count'])}   --- 亦可用对象
 *      -
 *      B、 @getter
 *          有时候我们需要在state中 >--派生--< 出一些状态，列入对列表进行过滤并计数
 *          用import { mapState, mapGetters } from 'vuex'  引入
 *          在组件中，（对象展开运算符） 将这些属性合并单计算属性中去
 *            computed：{
 *              localMethods () {},
 *                ...mapGetters(['count','done'])              ---- 同名映射
 *                ...mapGetters({name: 'count',key: 'done'})   ---- 采用对象形式
 *            }
 *       -
 *      C、 @mutations
 *          1, 更改Vuex的store中的状态的唯一方法就是提交mutation
 *               this.$store.commit('increment')
 *          2, 提交载荷
 *              你可以向store.commit 传入额外的参数， 即mutation的载荷（ payload ）
 *              mutations:{
 *                increment(state, n){
 *                  state.count+=n;
 *                }
 *              }
 *              this.$store.commit('increment',10)
 *
 *                也可以采取对象的方式 :
 *                   this.$store.commit({
 *                      type:'increment'
 *                      amount:10
 *                    })
 *
 *             3, 规则 --- （Mutation 需遵守vue的响应规则）
 *                  a, 最好提前在store中初始化好所有的属性
 *                  b, 当需要在对象上添加新的属性时
 *                      --- 使用 Vue.set(obj, ''newProp, 123);
 *                      --- 以新对象代替旧对象
 *                              state.obj = {...state.obj,newProp:123 }
 *                  c, Mutation 必须为同步函数（实质上任何在回调函数中进行的状态的改变都是不可）
 *                  d, mapMutation -- 亦可支持对象形式 (  map就是一种映射（也支持载荷）  将 this.add(12) 映射为  this.$store.commit('increment',12))
 *       D, action
 *          1, action 类似于mutation  action提交的是mutation，而不是直接更改状态
 *          2, action可以包含任意异步操作
 *          3, action 函数接受一个与store实例具有相同方法和属性的context对象
 *             在实际操作中我们经常用ES2015 --参数结构--来简化代码
 *              actions:{
 *                increment : ({ commit }) {
 *                  setTimeout(()=>{
 *                    commit('increment')
 *                  },500)
 *                }
 *              }
 *           -
 *          4, 分发action --（调用action）  store.dispatch('increment')
 *             actions 支持同样的载荷方式和对象方式进行分发
 *               --- 以载荷方式进行分发
 *                       store.dispatch('increment',{amount:10})
 *               --- 以对象的方式进行分发
 *                       store.dispatch({
 *                          type:   'increment',
 *                          amount: 10
 *                       })
 *          5, 购物实例
 *             actions：{
 *                checkout({ commit, state },products){
 *                  const saveCartItems = [ ...state.cart.added]
 *                  commit(types.CHECKOUT_REQUEST)
 *                  shop.buyProducts(
 *                    products,
 *                    ()=>commit(types.CHECKOUT_SUCCESS),
 *                    ()=>commit(types.CHECKOUT_FAILURE,saveCartItems)
 *                  )
 *                }
 *             }
 *          -
 *           6, mapAction
 *                ...mapActions(['increment'])  --可以载荷
 *                ...mapActions({ad:'increment'})
 *          -
 *           7, 组合action
 *                -- store.dispatch 可以处理被触发的action的处理函数返回的Promise，
 *                    并且store.dispatch 仍旧返回Promise
 *                    例: actions:{
 *                      actions({ commit }){
 *                        return new Promise((resolve,reject)=>{
 *                          setTimeout(()=>{
 *                            commit('someMutation')
 *                            resolve()
 *                          },1000)
 *                        })
 *                      }
 *                    }
 *                    -----调用：
 *                             store.dispatch('actionA').then(()=>{
 *                                   //..
 *                              })
 *                    ------也可以在另一个action
 *                            actions:{
 *                              //..
 *                              actionB({dispatch, commit }){
 *                                return dispatch('actions').then(()=>{
 *                                  commit('someOtherMutation')
 *                                })
 *                              }
 *                            }
 *                  -
 *                  -----actions:{
 *                          async actionA({commit}){
 *                              commit('gotData', await getData())
 *                          },
 *                          async actionB({commit}){
 *                              await dispatch('actionA')  // 等待actionA完成
 *                              commit('gotOtherData', await getOtherData())
 *                          }
 *                  }
 *                  一个store.dispatch在不同模块中可以触发多个action. 在这种情况下，
 *                  只有当所有触发函数完成后，返回的Promise才执行
 *                  -
 *                 -默认 模块action，mutation, getter,  --全局命名空间-- 使得多个模块对同一
 *                  的mutation或action作出响应
 *                  添加： namespace:true  使其成为命名空间模块， 后个 g, a, m, 都会自动
 *                  根据注册的路径调整命名
 *                    例：
 *                      const store = new Vuex.Store({
 *                          modules:{
 *                            account:{
 *                              namespace:true,
 *                              state:{ ... }   //模块内的状态已经嵌套了，使用'namespace' 属性不会对其产生影响
 *                              getters:{
 *                                isAdmin(){ ... }  //->getter['account/isAdmin']
 *                              },
 *                              actions:{
 *                                login(){ ... }    //->dispatch('account/login')
 *                              },
 *                              // 嵌套模块
 *                              module:{
 *                                  //继承父模块的命名空间
 *                               myPage:{
 *                                state:{ ... },
 *                                getters: {
 *                                    profile(){ ... }   //-> getters['account/profile']
 *                                },
 *                                actions: { ... }
 *                               },
 *                               posts:{
 *                                  namespace:true,
 *                                  state:{ ... },
 *                                  getters:{
 *                                    popular(){ ... } //-> getter['account/posts/popular']
 *                                  }
 *                               }
 *                              }
 *                            }
 *                          }
 *                      })
 *                      --------------------总结-------：模块添加namespace:true,模块空间命名， 可以无限嵌套。
 *                在命名空间模块内访问全局内容（ Global Assets ） rootState,rootGetter(作为第三，四参数传入getter)
 *                ,也会通过context对象的属性传入action
 *                -
 *                modules:{
 *                  foo:{
 *                    namespace:true,
 *                    getters:{
 *                        // 在这个模块的getter中，'getters' 被局部化了
 *                        // 可以使用getter 第四个参数来调用 'rootGetters'
 *                        someGetter(state, getters, rootState, rootGetters){
 *                          getters.someOtherGetter // -> foo/someOtherGetter
 *                          rootGetters.someOtherGetter // -> 'someOtherGetter'
 *                        },
 *                        someOtherGetter: state=>{ ... }
 *                    },
 *                    actions: {
 *                        // 在这个模块中， dispatch和commit 也被局部化了
 *                        // 他们可以接受 'root' 属性以访问 dispatch 或 commit
 *                        someAction({ dispatch, commit, getters, rootGetters }){
 *                          getters.someGetter // -> 'foo/someGetter'
 *                          rootGetters: someGetter // -> 'someGetter'
 *                                dispatch('someOtherAction') //->  'foo/someOtherAction'
 *                                dispatch('someOtherAction', null, { root: true}) //->  'someOtherAction'
 *                                commit('someMutation')   //-> 'foo/someMutation'
 *                                commit('someMutation', null, { root: true})      //-> 'someMutation'
 *                        },
 *                        someOtherAction(ctx, payload){ ... }
 *                    }
 *                  }
 *                }
 *                带有命名空间的绑定函数
 *                      当使用mapState, mapGetter, mapActions, mapMutations 这些函数来绑定命名空间模块，写起来可能比较麻烦
 *                      -
 *                      computed:{
 *                         ...mapState({
 *                            a:state => state.some.nested.module.a
 *                            b:state => state.some.nested.module.b
 *                         })
 *                      },
 *                     methods:{
 *                        ...mapActions([
 *                            'some/nests/module/foo',
 *                            'some/nests/module/bar'
 *                        ])
 *                     }
 *
 *                     ------------简写：----------
 *                     computed:{
 *                          ...mapState('some/nests/module',{
 *                              a: state => state.a
 *                              b: state => state.b
 *                          })
 *                     },
 *                     methods:{
 *                         ...mapActions('some/nested/module',{
 *                            'foo',
 *                            'bar'
 *                         })
 *                     }
 *                     -------------或： 简写 -----------------
 *                       import { createNamespacedHelpers }  from 'vuex'
 *                       const { mapState, mapActions } = createNamespacedHlepers('some/nests/module')
 *                       -
 *                       export default {
 *                          computed: {
 *                              // 在'some/nests/module' 中查找
 *                              ...mapState({
 *                                a:state => state.a,
 *                                b:state => state.b,
 *                              })
 *                          },
 *                          methods: {
 *                              // 在 'some/nests/module' 中查找
 *                              ...mapActions([
 *                                  'foo',
 *                                  'bar'
 *                              ])
 *                          }
 *                       }
 *                    ------------------模块动态注册-------------------------
 *                        在Store创建之后，你可以使用store.registerModule方法注册模块
 *                            //注册模块 'myModule'
 *                            store.registerModule('myModule',{
 *                                //...
 *                            })
 *                            //注册嵌套模块 'nested/myModule'
 *                            store.registerModule(['nested', 'myModule'],{
 *                                // ...
 *                            })
 *                         之后就可以通过 store.state.myModule 和 store.state.nests.myModule 访问模块的状态，
 *                         -------模块注册功能使得vue插件可以通过在store中附加新模块的方式来使用Vuex管理状态。
 *                           如， vuex-router-sync 插件 就是通过动态注册模块将vue-router 和 vuex 结合在一起。
 *                             实现运用路由管理状态。
 *                           也可以使用 store.unregisterModule(moduleName) 来动态卸载模块。不能卸载静态模块（
 *                           即 创建store时申明的模块）
 *                         -
 *                         在注册新module时，我们很有可能想保留过去state，例如从服务器端渲染的应用保留state。
 *                         你可以通过preserveState选项将其归档： store.registerModule('a', module, {preserveState:  true })
 *                 -
 *                 Vuex的store接受plugins选项，这个选项暴露出每次的mutation的钩子,vuex 插件就是一个函数，它接受store作为我一参数
 *                    -
 *                    const myPlugin = store =>{
 *                        // 当store 初始化后调用
 *                        store.subscribe((mutation, state)=>{
 *                            // 每次mutation 之后调用
 *                            // mutation 的格式为{type, payload }
 *                        })
 *                    }
 *                    -------------使用---------------
 *                     const store = new Vuex.Store({
 *                        // ...
 *                        plugins: [ myPlugin ]
 *                     })
 *                  -
 *            表单处理：
 *            <input :value='message' @input='updateMessage'></input>   //input 或者 change事件
 *            -
 *            computed: {
 *                ...mapState({
 *                      message: state => state.obj.message
 *                })
 *            },
 *            methods: {
 *                updateMessage(e) {
 *                    this.$store.commit('updateMessage',e.target.value)
 *                }
 *            }
 *            -
 *            ------方法二--------
 *                <input v-model='message'>
 *                  -
 *                  computed:{
 *                      message: {
 *                        get(){
 *                           return this.$store.state.obj.message
 *                        },
 *                        set(value){
 *                           return this.$store.commit('updateMessage',value)
 *                        }
 *                      }
 *                  }
 *    @type {Store}
 */

const store = new Vuex.Store({
  state,
  getters,
  mutations,
  actions,
  modules: {
    cart,
    products
  }
})

export default store
